package org.desktop.diskutils.business.files.factory.impl;

import java.io.IOException;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;

import org.desktop.diskutils.business.categories.IFileCategory;
import org.desktop.diskutils.business.files.IFileTree;
import org.desktop.diskutils.business.files.factory.ITreeFactory;
import org.desktop.diskutils.business.files.impl.FileTree;
import org.desktop.diskutils.business.files.impl.FileTreeNode;

public class PathTreeFactory implements ITreeFactory {

	@Override
	public IFileTree build(final String path, final IFileCategory rootCategory) {
		TreeBuilderMapVisitor visitor = new TreeBuilderMapVisitor();
		try {
			Files.walkFileTree(Paths.get(path), visitor);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		FileTree result = visitor.getTree();
		result.setRootCategory(rootCategory);
		return result;
	}

	private class TreeBuilderMapVisitor extends SimpleFileVisitor<Path> {
		private FileTree tree;
		private FileTreeNode activeNode = null;

		@Override
		public FileVisitResult visitFile(Path file, BasicFileAttributes attr) throws IOException {
			if (attr.isRegularFile()) {
				activeNode.addChild(file.getFileName().toString(), Files.size(file));
			}
			return FileVisitResult.CONTINUE;
		}

		@Override
		public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
			Path fileName = dir.getFileName();
			String name = fileName != null ? fileName.toString() : dir.toString();
			if (activeNode == null) {
				activeNode = new FileTreeNode(name, tree);
				tree = new FileTree(dir.toAbsolutePath().toString(), activeNode);
			} else {
				activeNode = activeNode.addChild(name);
			}

			return FileVisitResult.CONTINUE;
		}

		@Override
		public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
			activeNode = activeNode.getParent() != null ? activeNode.getParent() : activeNode;
			return FileVisitResult.CONTINUE;
		}

		@Override
		public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {
			exc.printStackTrace();
			return FileVisitResult.CONTINUE;
		}

		public FileTree getTree() {
			return tree;
		}
	}

}
